/// *
// * Copyright 2010-2012 VMware and contributors
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
// package cn.wenhao.javaClassReload.ReWrites;
//
// import java.lang.reflect.Modifier;
// import java.util.logging.Level;
// import java.util.logging.Logger;
//
// import org.objectweb.asm.ClassReader;
// import org.objectweb.asm.ClassVisitor;
// import org.objectweb.asm.ClassWriter;
// import org.objectweb.asm.FieldVisitor;
// import org.objectweb.asm.Label;
// import org.objectweb.asm.MethodVisitor;
// import org.objectweb.asm.Opcodes;
// import org.springsource.loaded.TypeRegistry.CouldBeReloadableDecision;
// import org.springsource.loaded.TypeRegistry.ReloadableTypeNameDecision;
// import org.springsource.loaded.Utils.ReturnType;
//
//
/// **
// * Rewrites a class such that it is amenable to reloading. This involves:
// * <ul>
// * <li>In every method, introduce logic to check it it the latest version of that method - if it isn't dispatch to the
// * latest
// * <li>Creates additional methods to aid with field setting/getting
// * <li>Creates additional fields to help reloading (reloadable type instance, new field value holders)
// * <li>Creates catchers for inherited methods. Catchers are simply passed through unless a new version of the class
// * provides an implementation
// * </ul>
// *
// * @author Andy Clement
// * @since 0.5.0
// */
// public class TypeRewriter implements Constants {
//
// private static Logger log = Logger.getLogger(TypeRewriter.class.getName());
//
// public static byte[] rewrite(ReloadableType rtype, byte[] bytes) {
// ClassReader fileReader = new ClassReader(bytes);
// RewriteClassAdaptor classAdaptor = new RewriteClassAdaptor(rtype);
// fileReader.accept(classAdaptor, 0);
// return classAdaptor.getBytes();
// }
//
// static class RewriteClassAdaptor extends ClassVisitor implements Constants {
//
// private ClassWriter cw;
//
// private String slashedname;
//
// private ReloadableType rtype;
//
// private TypeDescriptor typeDescriptor;
//
// private boolean clinitDone = false;
//
// private String supertypeName;
//
// private boolean isInterface;
//
// private int isTopmostReloadable = -1; // -1 = not computed. 0=false, 1=true
//
// private boolean isEnum;
//
// private boolean isGroovy;
//
// public RewriteClassAdaptor(ReloadableType rtype) {
// this(rtype, new ClassWriter(ClassWriter.COMPUTE_MAXS));
// }
//
// public RewriteClassAdaptor(ReloadableType rtype, ClassWriter classWriter) {
// super(ASM5, classWriter);
// this.rtype = rtype;
// this.slashedname = rtype.getSlashedName();
// this.cw = (ClassWriter) cv;
// this.typeDescriptor = rtype.getTypeDescriptor();
// this.isInterface = typeDescriptor.isInterface();
// this.isEnum = typeDescriptor.isEnum();
// this.isGroovy = typeDescriptor.isGroovyType();
// }
//
// public byte[] getBytes() {
// return cw.toByteArray();
// }
//
// public ClassVisitor getClassVisitor() {
// return cw;
// }
//
// @Override
// public void visit(int version, int access, String name, String signature, String superName,
// String[] interfaces) {
// access = Utils.promoteDefaultOrPrivateOrProtectedToPublic(access);
// super.visit(version, access, name, signature, superName, interfaces);
//
// this.supertypeName = superName;
// // Extra members in a reloadable type
// createReloadableTypeField();
// if (GlobalConfiguration.fieldRewriting) {
// if (!isInterface) {
// if (isTopmostReloadable()) {
// createInstanceStateManagerInstance();
// }
// createInstanceFieldGetterMethod();
// createInstanceFieldSetterMethod();
// createStaticFieldSetterMethod();
// createStaticFieldGetterMethod();
// createStaticInitializerForwarderMethod();
// }
// if (isTopmostReloadable()) {
// createStaticStateManagerInstance();
// }
// }
// if (!isInterface) {
// createManagedConstructors();
// createDispatcherCallingInitCtors();
// }
// }
//
// /**
// * Determine if this type is the top most reloadable type. Some state is only inserted into the top most
// * reloadable type in a hierarchy, rather than into every reloadable type. Typically this type will be the top
// * most reloadable if the supertype comes from a jar or is in a package we know is not reloadable (e.g.
// * java.lang).
// *
// * @return true if top most reloadable
// */
// private boolean isTopmostReloadable() {
// if (isTopmostReloadable > -1) {
// return isTopmostReloadable == 1;
// }
// boolean result = false;
// TypeRegistry typeRegistry = rtype.getTypeRegistry();
// String supertypeName = typeDescriptor.getSupertypeName();
// ReloadableTypeNameDecision rtnd = typeRegistry.isReloadableTypeName(supertypeName, null, null);
// if (rtnd.isReloadable) {
// // If splitPackages option is turned ON or super type is being explicitly included via pattern,
// // dig a bit deeper. It may still be excluded due to being in a non watched jar. (So effectively the
// // inclusion pattern does not apply to jar contents).
// if (GlobalConfiguration.allowSplitPackages || rtnd.explicitlyIncluded) {
// CouldBeReloadableDecision cbrd = rtnd.cbrd;
// if (cbrd == null) {
// cbrd = typeRegistry.couldBeReloadable(supertypeName, false);
// }
// result = !cbrd.couldBeReloadable;
// }
// else {
// result = false;
// }
// }
// else {
// result = true;
// }
// isTopmostReloadable = result ? 1 : 0;
// return result;
//
// // this would work if the supertype was always guaranteed to be dealt with before this type
// // return typeRegistry.getReloadableType(typeDescriptor.getSupertypeName(), false) == null;
//
// // original decision:
// // This makes a mistake for split packages
// // if (!typeRegistry.isReloadableTypeName(supertypeName)) {
// // return true;
// // }
// // else {
// // return false;
// // }
// }
//
// private void createStaticInitializerForwarderMethod() {
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC_STATIC, mStaticInitializerName, "()V", null, null);
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(INVOKEVIRTUAL, tReloadableType, "fetchLatest", "()Ljava/lang/Object;");
// mv.visitTypeInsn(CHECKCAST, Utils.getInterfaceName(slashedname));
// mv.visitMethodInsn(INVOKEINTERFACE, Utils.getInterfaceName(slashedname), mStaticInitializerName, "()V");
// mv.visitInsn(RETURN);
// mv.visitMaxs(1, 0);
// mv.visitEnd();
// }
//
// // TODO review whether we get these up and down the hierarchy or just at the top?
// /**
// * Create the static field getter method which ensures the static state manager is initialized.
// */
// private void createStaticFieldGetterMethod() {
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC_STATIC, mStaticFieldGetterName,
// "(Ljava/lang/String;)Ljava/lang/Object;",
// null, null);
// mv.visitFieldInsn(GETSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// Label l2 = new Label();
// mv.visitJumpInsn(IFNONNULL, l2);
// mv.visitTypeInsn(NEW, tStaticStateManager);
// mv.visitInsn(DUP);
// mv.visitMethodInsn(INVOKESPECIAL, tStaticStateManager, "<init>", "()V");
// mv.visitFieldInsn(PUTSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// mv.visitLabel(l2);
// mv.visitFieldInsn(GETSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitMethodInsn(INVOKEVIRTUAL, tStaticStateManager, "getValue", "(" + lReloadableType
// + "Ljava/lang/String;)Ljava/lang/Object;");
// mv.visitInsn(ARETURN);
// mv.visitMaxs(3, 2);
// mv.visitEnd();
// }
//
// private void createDispatcherCallingInitCtors() {
// MethodMember[] ctors = typeDescriptor.getConstructors();
// for (MethodMember ctor : ctors) {
// String desc = ctor.getDescriptor();
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "___init___", desc, null, null);
// mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitInsn(ICONST_1);
// mv.visitMethodInsn(INVOKEVIRTUAL, tReloadableType, "getLatestDispatcherInstance",
// "(Z)Ljava/lang/Object;");
// mv.visitTypeInsn(CHECKCAST, Utils.getInterfaceName(slashedname));
// String desc2 = new StringBuffer("(L").append(slashedname).append(";").append(
// desc.substring(1)).toString();
// mv.visitVarInsn(ALOAD, 0);
// Utils.createLoadsBasedOnDescriptor(mv, desc, 1);
// mv.visitMethodInsn(INVOKEINTERFACE, Utils.getInterfaceName(slashedname), "___init___", desc2);
// mv.visitInsn(RETURN);
// mv.visitMaxs(3, Utils.getParameterCount(desc) + 1);
// mv.visitEnd();
// }
// }
//
// private void createManagedConstructors() {
// String slashedSupertypeName = typeDescriptor.getSupertypeName();
// if (slashedSupertypeName.equals("java/lang/Enum")) { // assert isEnum
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>",
// "(Ljava/lang/String;ILorg/springsource/loaded/C;)V", null,
// null);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitVarInsn(ALOAD, 1);
// mv.visitVarInsn(ILOAD, 2);
// mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Enum", "<init>", "(Ljava/lang/String;I)V");
// mv.visitInsn(RETURN);
// mv.visitMaxs(3, 3);
// mv.visitEnd();
// return;
// }
//
// if (slashedSupertypeName.equals("groovy/lang/Closure")) { // assert this is a closure
// // create the special constructor we want to use, not the one below
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>",
// "(Ljava/lang/Object;Ljava/lang/Object;Lorg/springsource/loaded/C;)V", null, null);
// TypeDescriptor superDescriptor = rtype.getTypeRegistry().getDescriptorFor(supertypeName);
// MethodMember ctor = superDescriptor.getConstructor("(Ljava/lang/Object;Ljava/lang/Object;)V");
// if (ctor == null) {
// throw new IllegalStateException("Unable to find expected constructor on Closure type");
// }
// mv.visitVarInsn(ALOAD, 0); // this (uninitialized)
// mv.visitVarInsn(ALOAD, 1); // 'owner'
// mv.visitVarInsn(ALOAD, 2); // 'this'
// mv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Closure", "<init>",
// "(Ljava/lang/Object;Ljava/lang/Object;)V");
// mv.visitInsn(RETURN);
// mv.visitMaxs(3, 4);
// mv.visitEnd();
// }
// else {
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/springsource/loaded/C;)V", null, null);
// mv.visitVarInsn(ALOAD, 0);
// if (slashedSupertypeName.equals("java/lang/Object")) {
// mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
// mv.visitInsn(RETURN);
// mv.visitMaxs(1, 2);
// }
// else if (slashedSupertypeName.equals("java/lang/Enum")) { // assert isEnum
// // Call Enum.<init>(null,0)
// mv.visitInsn(ACONST_NULL);
// mv.visitLdcInsn(0);
// mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Enum", "<init>", "(Ljava/lang/String;I)V");
// mv.visitInsn(RETURN);
// mv.visitMaxs(3, 3);
// }
// else {
// ReloadableType superRtype = rtype.getTypeRegistry().getReloadableType(slashedSupertypeName);
// if (superRtype == null) {
// // This means we are crossing a reloadable boundary (this type is reloadable, the supertype is not).
// // At this point we may be in trouble. The only time we'll be OK is if the supertype declares a no-arg lructor
// // we can see from here
// TypeDescriptor superDescriptor = rtype.getTypeRegistry().getDescriptorFor(supertypeName);
// MethodMember ctor = superDescriptor.getConstructor("()V");
// if (ctor != null) {
// mv.visitMethodInsn(INVOKESPECIAL, slashedSupertypeName, "<init>", "()V");
// }
// else {
// String warningMessage = "SERIOUS WARNING (current limitation): At reloadable boundary of "
// + typeDescriptor.getDottedName()
// + " supertype="
// + supertypeName
// + " - no available default ctor for that supertype, problems may occur on reload if constructor changes";
// if (GlobalConfiguration.isRuntimeLogging && log.isLoggable(Level.SEVERE)) {
// log.log(Level.SEVERE, warningMessage);
// }
// // suppress for closure subtypes
// if (!(supertypeName.equals("groovy/lang/Closure")
// || supertypeName.startsWith("org/codehaus/groovy/runtime/callsite"))) {
// if (GlobalConfiguration.verboseMode) {
// System.out.println(warningMessage);
// }
// }
// // TODO [verify] running enumtests we see that there is an issue here with leaving the special constructor without a
/// super call in it.
// // this will fail verification.
//
// // throw new IllegalStateException("at reloadable boundary, not sure how to construct " + supertypeName);
// }
// }
// else {
// mv.visitInsn(ACONST_NULL);
// mv.visitMethodInsn(INVOKESPECIAL, slashedSupertypeName, "<init>",
// "(Lorg/springsource/loaded/C;)V");
// }
// mv.visitInsn(RETURN);
// mv.visitMaxs(2, 2);
// }
// mv.visitEnd();
// }
//
// }
//
// /**
// * Create the static field setter method. Looks a bit like this:
// * <p>
// * <code><pre>
// * public static r$sets(Object newValue, String name) {
// * if (r$fields==null) {
// * r$fields = new SSMgr();
// * }
// * r$fields.setValue(reloadableTypeInstance, newValue, name);
// * }
// * </pre></code>
// */
// private void createStaticFieldSetterMethod() {
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC_STATIC, mStaticFieldSetterName, mStaticFieldSetterDescriptor,
// null, null);
// mv.visitFieldInsn(GETSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// Label l2 = new Label();
// mv.visitJumpInsn(IFNONNULL, l2);
// mv.visitTypeInsn(NEW, tStaticStateManager);
// mv.visitInsn(DUP);
// mv.visitMethodInsn(INVOKESPECIAL, tStaticStateManager, "<init>", "()V", false);
// mv.visitFieldInsn(PUTSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// mv.visitLabel(l2);
// mv.visitFieldInsn(GETSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitVarInsn(ALOAD, 1);
// mv.visitMethodInsn(INVOKEVIRTUAL, tStaticStateManager, "setValue", "(" + lReloadableType
// + "Ljava/lang/Object;Ljava/lang/String;)V", false);
// mv.visitInsn(RETURN);
// mv.visitMaxs(4, 2);
// mv.visitEnd();
// }
//
// /**
// * Create the instance field getter method. Looks a bit like this:
// * <p>
// * <code><pre>
// * public Object r$get(Object instance, String name) {
// * if (this.instanceStateManager==null) {
// * this.instanceStateManager = new InstanceStateManager();
// * }
// * return this.instanceStateManager.getValue(reloadableType,instance,name);
// * }
// * </pre></code>
// */
// private void createInstanceFieldGetterMethod() {
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, mInstanceFieldGetterName, mInstanceFieldGetterDescriptor,
// null, null);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(GETFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// Label l1 = new Label();
// mv.visitJumpInsn(IFNONNULL, l1);
// // instance state manager will only get initialised here if the constructor did not do it
// mv.visitVarInsn(ALOAD, 0);
// mv.visitTypeInsn(NEW, tInstanceStateManager);
// mv.visitInsn(DUP);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(INVOKESPECIAL, tInstanceStateManager, "<init>",
// "(Ljava/lang/Object;Lorg/springsource/loaded/ReloadableType;)V");
// mv.visitFieldInsn(PUTFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// mv.visitLabel(l1);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(GETFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitVarInsn(ALOAD, 1);
// mv.visitVarInsn(ALOAD, 2);
// mv.visitMethodInsn(INVOKEVIRTUAL, tInstanceStateManager, "getValue", "(" + lReloadableType
// + "Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");
// mv.visitInsn(ARETURN);
// mv.visitMaxs(4, 3);
// mv.visitEnd();
// }
//
// private final static int lvThis = 0;
//
// // TODO [perf] shuffle ordering of value/instance passed in here to speed up things? (see also rewritePUTFIELD) can
/// we reduce/remove swap
// /**
// * Create a field setter for instance fields, signature of: public void r$set(Object,Object,String)
// */
// private void createInstanceFieldSetterMethod() {
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, mInstanceFieldSetterName, mInstanceFieldSetterDescriptor,
// null, null);
// final int lvNewValue = 1;
// final int lvInstance = 2;
// final int lvName = 3;
// mv.visitVarInsn(ALOAD, lvThis);
// mv.visitFieldInsn(GETFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// // Will only get initialised here if the constructor did not do it
// Label l1 = new Label();
// mv.visitJumpInsn(IFNONNULL, l1);
// // Initialise the Instance State Manager
// mv.visitVarInsn(ALOAD, lvThis);
// mv.visitTypeInsn(NEW, tInstanceStateManager);
// mv.visitInsn(DUP);
// mv.visitVarInsn(ALOAD, lvThis);
// mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(INVOKESPECIAL, tInstanceStateManager, "<init>",
// "(Ljava/lang/Object;Lorg/springsource/loaded/ReloadableType;)V");
// mv.visitFieldInsn(PUTFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// mv.visitLabel(l1);
//
// // get the instance state manager object
// mv.visitVarInsn(ALOAD, lvThis);
// mv.visitFieldInsn(GETFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
//
// // get the reloadable type
// mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
//
// // TODO [perf] do we need to pass reloadabletype? Shouldn't the ISMgr instance know it!
// // call setValue
// mv.visitVarInsn(ALOAD, lvInstance);
// mv.visitVarInsn(ALOAD, lvNewValue);
// mv.visitVarInsn(ALOAD, lvName);
// // setValue(ReloadableType rtype, Object instance, Object value, String name)
// mv.visitMethodInsn(INVOKEVIRTUAL, tInstanceStateManager, "setValue", "(" + lReloadableType
// + "Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/String;)V");
// mv.visitInsn(RETURN);
// mv.visitMaxs(4, 4);
// mv.visitEnd();
// }
//
// private void createInstanceStateManagerInstance() {
// FieldVisitor f = cw.visitField(ACC_PUBLIC | ACC_TRANSIENT, fInstanceFieldsName, lInstanceStateManager,
// null, null);
// f.visitEnd();
// }
//
// private void createStaticStateManagerInstance() {
// FieldVisitor f = cw.visitField(ACC_PUBLIC_STATIC /*| ACC_TRANSIENT*/ | ACC_FINAL, fStaticFieldsName,
// lStaticStateManager, null, null);
// f.visitEnd();
// }
//
// /**
// * Create the reloadable type field, which can later answer questions about changes or be used to access the
// * latest version of a type/method.
// */
// private void createReloadableTypeField() {
// int acc = isInterface ? ACC_PUBLIC_STATIC_FINAL : ACC_PUBLIC_STATIC; //ACC_PRIVATE_STATIC;
// FieldVisitor fv = cw.visitField(acc, fReloadableTypeFieldName, lReloadableType, null, null);
// fv.visitEnd();
// }
//
// @Override
// public MethodVisitor visitMethod(int flags, String name, String descriptor, String signature,
// String[] exceptions) {
// MethodVisitor mv = super.visitMethod(promoteIfNecessary(flags, name), name, descriptor, signature,
// exceptions);
// MethodVisitor newMethodVisitor = getMethodVisitor(name, descriptor, mv);
// return newMethodVisitor;
// }
//
// public MethodVisitor getMethodVisitor(String name, String descriptor, MethodVisitor mv) {
// MethodVisitor newMethodVisitor = null;
// if (name.charAt(0) == '<') {
// if (name.charAt(1) == 'c') { // <clinit>
// clinitDone = true;
// newMethodVisitor = new MethodPrepender(mv, new ClinitPrepender(mv));
// }
// else { // <init>
// newMethodVisitor = new AugmentingConstructorAdapter(mv, descriptor, slashedname,
// isTopmostReloadable());
// // want to create a copy of the constructor called ___init___ so it is reachable from the executor of the subtype.
// // All it really needs to do is call through the dispatcher to the executor for the relevant constructor.
// // this will force a reload of the supertype (to create the super executor) - that is something we can address later
// }
// }
// else {
// // what about just copying if isgroovy and name.startsWith("$get");
// // Can't do this for $getStaticMetaClass so let us use $get$$ for now, until we discover why that lets us down...
// // if (isGroovy && name.startsWith("$get$$")) {
// // newMethodVisitor = new MethodAdapter(mv);
// // } else {
// newMethodVisitor = new AugmentingMethodAdapter(mv, name, descriptor);
// // }
// }
// return newMethodVisitor;
// }
//
// // Default visibility elements need promotion to public so that they can be seen from the executor
// private int promoteIfNecessary(int flags, String name) {
// int newflags = Utils.promoteDefaultOrProtectedToPublic(flags, isEnum, name);
// return newflags;
// }
//
// @Override
// public FieldVisitor visitField(final int access, final String name, final String desc, final String signature,
// final Object value) {
// // Special casing here for serialVersionUID - not removing the final modifier. This enables
// // the code in java.io.ObjectStreamClass to access it.
// int modAccess = 0;
// if ((access & ACC_FINAL) != 0) {
// if (name.equals("serialVersionUID")) {
// modAccess = (access & ~(ACC_PRIVATE | ACC_PROTECTED)) | ACC_PUBLIC;
// }
// else {
// // remove final
// modAccess = (access & ~(ACC_PRIVATE | ACC_PROTECTED)) | ACC_PUBLIC;
// modAccess = modAccess & ~ACC_FINAL;
// }
// }
// else {
// // remove final
// modAccess = (access & ~(ACC_PRIVATE | ACC_PROTECTED)) | ACC_PUBLIC;
// modAccess = modAccess & ~ACC_FINAL;
// }
// return cv.visitField(modAccess, name, desc, signature, value);
// }
//
// static class FieldHolder {
//
// final int access;
//
// final String name;
//
// final String desc;
//
// public FieldHolder(int access, String name, String desc) {
// this.access = access;
// this.name = name;
// this.desc = desc;
// }
// }
//
// @Override
// public void visitEnd() {
// if (!clinitDone) {
// // Need to add a static initializer to initialize the reloadable type field
// MethodVisitor mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
// new ClinitPrepender(mv).prepend();
// mv.visitInsn(RETURN);
// mv.visitMaxs(3, 0);
// mv.visitEnd();
// }
// generateCatchers();
// generateDynamicDispatchHandler();
// cv.visitEnd();
// }
//
// /**
// * Create a basic dynamic dispatch handler. To support changes to interfaces, a new method is added to all
// * reloadable interfaces and this needs an implementation. This method generates the implementation which
// * delegates to the reloadable interface for the type. As interfaces can't get static methods we only have to
// * worry about instance methods here.
// */
// private void generateDynamicDispatchHandler() {
// final int indexThis = 0;
// final int indexArgs = 1;
// final int indexTargetInstance = 2;
// final int indexNameAndDescriptor = 3;
//
// if (isInterface) {
// cw.visitMethod(ACC_PUBLIC_ABSTRACT, mDynamicDispatchName, mDynamicDispatchDescriptor, null, null);
// }
// else {
// MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, mDynamicDispatchName, mDynamicDispatchDescriptor, null,
// null);
//
// // Sometimes we come into the dynamic dispatcher because we are handling an INVOKEINTERFACE for a method
// // not defined on the original interface. In these cases we will find that fetchLatest() returns null because
// // the interface was reloaded, but the implementation was not (necessarily). Should we force it to reload
// // the implementation? That would generate the correct dispatcher...
//
// // 1. Ask the reloadable type for the latest version of the interface
// // __DynamicallyDispatchable dispatchable = r$type.determineDispatcher(this,nameAndDescriptor)
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitVarInsn(ALOAD, indexThis);
// mv.visitVarInsn(ALOAD, indexNameAndDescriptor);
// mv.visitMethodInsn(INVOKEVIRTUAL, tReloadableType, "determineDispatcher",
// "(Ljava/lang/Object;Ljava/lang/String;)Lorg/springsource/loaded/__DynamicallyDispatchable;");
//
// mv.visitInsn(DUP);
// Label l1 = new Label();
// mv.visitJumpInsn(IFNULL, l1);
// {
// // 2. package up the parameters
// // can I assert that 0==2 - ie. the instance being called upon is the same as the parameter passed in
// mv.visitVarInsn(ALOAD, indexArgs);
// mv.visitVarInsn(ALOAD, indexThis);
// mv.visitVarInsn(ALOAD, indexNameAndDescriptor);
//
// // 3. call it
// // return dispatchable.__execute(parameters,this,nameAndDescriptor)
// mv.visitMethodInsn(INVOKEINTERFACE, "org/springsource/loaded/__DynamicallyDispatchable",
// mDynamicDispatchName,
// mDynamicDispatchDescriptor);
// mv.visitInsn(ARETURN);
// }
// mv.visitLabel(l1);
// mv.visitInsn(POP); // POPNULL
//
// // delegate to the superclass dynamic dispatch method
// // mv.visitVarInsn(ALOAD, 0);
// // mv.visitVarInsn(ALOAD, 1);
// // mv.visitVarInsn(ALOAD, 2);
// // mv.visitVarInsn(ALOAD, 3);
// // mv.visitMethodInsn(INVOKESPECIAL, supertypeName, mDynamicDispatchName, mDynamicDispatchDescriptor);
// // mv.visitInsn(ARETURN);
//
// // 4. throw NoSuchMethodError
// genThrowNoSuchMethodError(mv, indexNameAndDescriptor);
// mv.visitMaxs(5, 4);
// mv.visitEnd();
// }
// }
//
// /**
// * @param mv where to append the instructions
// * @param index the index of the String message to load and use in the exception
// */
// private final void genThrowNoSuchMethodError(MethodVisitor mv, int index) {
// mv.visitTypeInsn(NEW, "java/lang/NoSuchMethodError");
// mv.visitInsn(DUP);
// mv.visitVarInsn(ALOAD, index);
// mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V");
// mv.visitInsn(ATHROW);
// }
//
// /**
// * Catcher methods are 'empty' methods added to subtypes to 'catch' any virtual dispatch calls that would
// * otherwise be missed. Catchers then check to see if the type on which they are defined now provides an
// * implementation of the method in question - if it does then it is called, otherwise the catcher simply calls
// * the supertype.
// * <p>
// * Catchers typically have the same visibility as the methods for which they exist, unless those methods are
// * protected/default, in which case the catcher is made public. This enables them to be seen from the executor.
// */
// private void generateCatchers() {
// if (!GlobalConfiguration.catchersOn || isInterface) {
// return;
// }
// FieldMember[] fms = typeDescriptor.getFieldsRequiringAccessors();
//
// for (FieldMember field : fms) {
// createProtectedFieldGetterSetter(field);
// }
//
// MethodMember[] methods = typeDescriptor.getMethods();
//
// for (MethodMember method : methods) {
// if (!MethodMember.isSuperDispatcher(method)) {
// continue;
// }
// // TODO topmost test?
// String name = method.getName();
// String descriptor = method.getDescriptor();
// if (GlobalConfiguration.verboseMode && log.isLoggable(Level.FINEST)) {
// log.finest("Creating super dispatcher for method " + name + descriptor + " in type " + slashedname);
// }
// // Create a superdispatcher for this method
// MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, method.getName(), method.getDescriptor(), null,
// method.getExceptions());
// int ps = Utils.getParameterCount(method.getDescriptor());
// ReturnType methodReturnType = Utils.getReturnTypeDescriptor(method.getDescriptor());
// int lvarIndex = 0;
// mv.visitVarInsn(ALOAD, lvarIndex++); // load this
// Utils.createLoadsBasedOnDescriptor(mv, descriptor, lvarIndex);
// String targetMethod = method.getName().substring(0, method.getName().lastIndexOf("_$"));
// mv.visitMethodInsn(Opcodes.INVOKESPECIAL, typeDescriptor.getSupertypeName(), targetMethod,
// method.getDescriptor());
// Utils.addCorrectReturnInstruction(mv, methodReturnType, false);
// int maxs = ps + 1;
// if (methodReturnType.isDoubleSlot()) {
// maxs++;
// }
// mv.visitMaxs(maxs, maxs);
// mv.visitEnd();
// }
//
// for (MethodMember method : methods) {
// if (!MethodMember.isCatcher(method)) {
// continue;
// }
// String name = method.getName();
// String descriptor = method.getDescriptor();
// ReturnType returnType = Utils.getReturnTypeDescriptor(descriptor);
//
// // 1. Create the method signature
// int flags = method.getModifiers();
// if (Modifier.isProtected(flags)) {
// flags = flags - Modifier.PROTECTED + Modifier.PUBLIC;
// }
// MethodVisitor mv = cw.visitMethod(flags, method.getName(), method.getDescriptor(), null,
// method.getExceptions());
//
// // 2. Ask the type if anything has changed from first load
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitLdcInsn(method.getId());
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, tReloadableType, "fetchLatestIfExists",
// "(I)Ljava/lang/Object;");
//
// // If the return value is null, there is no implementation
// mv.visitInsn(DUP);
//
// // 3. create the if statement
// Label l1 = new Label();
// mv.visitJumpInsn(Opcodes.IFNULL, l1);
//
// // 4. if changed then call the interface to run whatever version has been added
// mv.visitTypeInsn(CHECKCAST, Utils.getInterfaceName(slashedname));
//
// int lvarIndex = 0;
// mv.visitVarInsn(ALOAD, lvarIndex++); // load this
// Utils.createLoadsBasedOnDescriptor(mv, descriptor, lvarIndex);
// String desc = new StringBuffer("(L").append(slashedname).append(";").append(
// descriptor.substring(1)).toString();
// mv.visitMethodInsn(INVOKEINTERFACE, Utils.getInterfaceName(slashedname), name, desc);
// Utils.addCorrectReturnInstruction(mv, returnType, true);
//
// // 5. if unchanged just run the supertype version (could be another catcher...)
// mv.visitLabel(l1);
// mv.visitInsn(POP);
// int ps = Utils.getParameterCount(method.getDescriptor());
// ReturnType methodReturnType = Utils.getReturnTypeDescriptor(method.getDescriptor());
//
// // A catcher for an interface method is inserted into abstract classes. These should never be reached unless
// // they now provide an implementation (on a reload) and the subtype has deleted the implementation it had.
// // This means there is never a need to call 'super' in the logic below and getting here when there isn't
// // something to run in the executor is a bug (so we throw AbstractMethodError)
// if (MethodMember.isCatcherForInterfaceMethod(method)) {
// mv.visitTypeInsn(NEW, "java/lang/IllegalStateException");
// mv.visitInsn(DUP);
// mv.visitMethodInsn(INVOKESPECIAL, "java/lang/AbstractMethodError", "<init>", "()V", false);
// mv.visitInsn(ATHROW);
// }
// else {
// mv.visitVarInsn(ALOAD, 0); // load this
// Utils.createLoadsBasedOnDescriptor(mv, method.getDescriptor(), 1);
// mv.visitMethodInsn(INVOKESPECIAL, supertypeName, method.getName(), method.getDescriptor(), false);
// Utils.addCorrectReturnInstruction(mv, methodReturnType, false);
// }
//
// int maxs = ps + 1;
// if (methodReturnType.isDoubleSlot()) {
// maxs++;
// }
// mv.visitMaxs(maxs, maxs);
// mv.visitEnd();
// }
//
// }
//
// private void insertCorrectLoad(MethodVisitor mv, ReturnType rt, int slot) {
// if (rt.isPrimitive()) {
// switch (rt.descriptor.charAt(0)) {
// case 'Z':
// case 'S':
// case 'I':
// case 'B':
// case 'C':
// mv.visitVarInsn(ILOAD, slot);
// break;
// case 'F':
// mv.visitVarInsn(FLOAD, slot);
// break;
// case 'J':
// mv.visitVarInsn(LLOAD, slot);
// break;
// case 'D':
// mv.visitVarInsn(DLOAD, slot);
// break;
// default:
// throw new IllegalStateException(rt.descriptor);
// }
// }
// else {
// mv.visitVarInsn(ALOAD, slot);
// }
// }
//
// /**
// * For the fields that need it (protected fields from a non-reloadable supertype), create the getters and
// * setters so that the executor can read/write them.
// *
// */
// private void createProtectedFieldGetterSetter(FieldMember field) {
// String descriptor = field.descriptor;
// String name = field.name;
// ReturnType rt = ReturnType.getReturnType(descriptor);
// if (field.isStatic()) {
// MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC | Modifier.STATIC,
// Utils.getProtectedFieldGetterName(name), "()"
// + descriptor,
// null, null);
// mv.visitFieldInsn(GETSTATIC, slashedname, name, descriptor);
// Utils.addCorrectReturnInstruction(mv, rt, false);
// mv.visitMaxs(rt.isDoubleSlot() ? 2 : 1, 0);
// mv.visitEnd();
//
// mv = cw.visitMethod(Modifier.PUBLIC | Modifier.STATIC, Utils.getProtectedFieldSetterName(name), "("
// + descriptor
// + ")V", null, null);
// insertCorrectLoad(mv, rt, 0);
// mv.visitFieldInsn(PUTSTATIC, slashedname, name, descriptor);
// mv.visitInsn(RETURN);
// mv.visitMaxs(rt.isDoubleSlot() ? 2 : 1, 1);
// mv.visitEnd();
// }
// else {
// MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, Utils.getProtectedFieldGetterName(name), "()"
// + descriptor,
// null, null);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(GETFIELD, slashedname, name, descriptor);
// Utils.addCorrectReturnInstruction(mv, rt, false);
// mv.visitMaxs(rt.isDoubleSlot() ? 2 : 1, 1);
// mv.visitEnd();
//
// mv = cw.visitMethod(Modifier.PUBLIC, Utils.getProtectedFieldSetterName(name), "(" + descriptor + ")V",
// null, null);
// mv.visitVarInsn(ALOAD, 0);
// insertCorrectLoad(mv, rt, 1);
// mv.visitFieldInsn(PUTFIELD, slashedname, name, descriptor);
// mv.visitInsn(RETURN);
// mv.visitMaxs(rt.isDoubleSlot() ? 3 : 2, 2);
// mv.visitEnd();
// }
// }
//
// /**
// * The ClinitPrepender adds the code to initialize the reloadable type field at class load
// */
// class ClinitPrepender implements Prepender, Constants {
//
// MethodVisitor mv;
//
// private final static String descriptorFor_getReloadableType = "(II)" + lReloadableType;
//
// private final static String descriptorFor_associateReloadableType = "(" + lReloadableType
// + "Ljava/lang/Class;)V";
//
// ClinitPrepender(MethodVisitor mv) {
// this.mv = mv;
// }
//
// public void prepend() {
// // Discover the ReloadableType object and store it here
// mv.visitCode();
// // TODO optimization: could collapse ints into one but this snippet isn't put in many places
// mv.visitLdcInsn(rtype.getTypeRegistryId());
// mv.visitLdcInsn(rtype.getId());
// mv.visitMethodInsn(INVOKESTATIC, tRegistryType, "getReloadableType", descriptorFor_getReloadableType,
// false);
//
// mv.visitFieldInsn(PUTSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// // mv.visitFieldInsn(GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// // mv.visitLdcInsn(Type.getObjectType(rtype.getSlashedSupertypeName()));//Type("L" + rtype.getSlashedSupertypeName()
/// + ";")); // faster way?
// // mv.visitMethodInsn(INVOKEVIRTUAL, tReloadableType, "setSuperclass", "(Ljava/lang/Class;)V");
//
// // only in the top most type - what about interfaces??
// if (GlobalConfiguration.fieldRewriting) {
// mv.visitFieldInsn(GETSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// Label l1 = new Label();
// mv.visitJumpInsn(IFNONNULL, l1);
// mv.visitTypeInsn(NEW, tStaticStateManager);
// mv.visitInsn(DUP);
// mv.visitMethodInsn(INVOKESPECIAL, tStaticStateManager, "<init>", "()V", false);
// mv.visitFieldInsn(PUTSTATIC, slashedname, fStaticFieldsName, lStaticStateManager);
// mv.visitLabel(l1);
// }
// // If the static initializer has changed, call the new version through the ___clinit___ method
//
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, tReloadableType, "clinitchanged", "()I", false);
// // 2. Create the if statement
// Label wasZero = new Label();
// mv.visitJumpInsn(Opcodes.IFEQ, wasZero); // if == 0, jump to where we can do the original thing
//
// // 3. grab the latest dispatcher and call it through the interface
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(INVOKEVIRTUAL, tReloadableType, "fetchLatest", "()Ljava/lang/Object;", false);
// mv.visitTypeInsn(CHECKCAST, Utils.getInterfaceName(slashedname));
// mv.visitMethodInsn(INVOKEINTERFACE, Utils.getInterfaceName(slashedname), mStaticInitializerName, "()V");
// mv.visitInsn(RETURN);
// // 4. do what you were going to do anyway
// mv.visitLabel(wasZero);
// }
// }
//
// /**
// * Rewrites a method to include the extra checks to verify it is the most up to date version.
// */
// class AugmentingMethodAdapter extends MethodVisitor implements Opcodes {
//
// int methodId;
//
// String name;
//
// String descriptor;
//
// MethodMember method;
//
// ReturnType returnType;
//
// public AugmentingMethodAdapter(MethodVisitor mv, String name, String descriptor) {
// super(ASM5, mv);
// this.name = name;
// this.method = rtype.getMethod(name, descriptor);
// this.methodId = method.getId();
// this.descriptor = descriptor;
// this.returnType = Utils.getReturnTypeDescriptor(descriptor);
// }
//
// @Override
// public void visitCode() {
// super.visitCode();
// boolean isStaticMethod = method.isStatic();
// // 1. ask the reloadable type if anything has changed since initial load by
// // calling 'int changed(int)' passing in the method ID
// // 0 if the method cannot have changed
// // 1 if the method has changed
// // 2 if the method has been deleted in a new version
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitLdcInsn(methodId);
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, tReloadableType, "changed", "(I)I");
// // 2. Create the if statement
// Label wasZero = new Label();
// if (!isStaticMethod) {
// mv.visitInsn(DUP);
// }
// mv.visitJumpInsn(Opcodes.IFEQ, wasZero); // if == 0, jump to where we can do the original thing
//
// // TODO if it isStatic then the invoke side should be pointing at the right version - do we need to cope with it not?
// if (!isStaticMethod) {
// Label wasOne = new Label();
// mv.visitInsn(ICONST_1);
// mv.visitJumpInsn(IF_ICMPEQ, wasOne); // if == 1, method has changed
// // If here, == 2, so method has been deleted
// // either try an invokespecial on a super or throw a NoSuchmethodError
//
// // Only worth including super.xxx() call if the supertype does define it or the supertype is reloadable
// // Otherwise we will generate invokespecial 'Object.somethingThatCantBeThere' in some cases
// TypeDescriptor superDescriptor = rtype.getTypeRegistry().getDescriptorFor(supertypeName);
// if (!superDescriptor.definesNonPrivate(name + descriptor)) {
// insertThrowNoSuchMethodError();
// }
// else {
// insertInvokeSpecialToCallSuperMethod();
// }
// mv.visitLabel(wasOne);
// }
// // 3. grab the latest dispatcher and call it through the interface
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(INVOKEVIRTUAL, tReloadableType, "fetchLatest", "()Ljava/lang/Object;");
// mv.visitTypeInsn(CHECKCAST, Utils.getInterfaceName(slashedname));
// int lvarIndex = 0;
// if (!isStaticMethod) {
// mv.visitVarInsn(ALOAD, lvarIndex++);
// }
// else {
// mv.visitInsn(ACONST_NULL);
// }
// Utils.createLoadsBasedOnDescriptor(mv, descriptor, lvarIndex);
// String desc = new StringBuilder("(L").append(slashedname).append(";").append(
// descriptor.substring(1)).toString();
// if (method.isStatic() && MethodMember.isClash(method)) {
// name = "__" + name;
// }
// mv.visitMethodInsn(INVOKEINTERFACE, Utils.getInterfaceName(slashedname), name, desc);
// Utils.addCorrectReturnInstruction(mv, returnType, true);
// // 4. do what you were going to do anyway
// mv.visitLabel(wasZero);
// if (!isStaticMethod) {
// mv.visitInsn(POP);
// }
// }
//
// private void insertInvokeSpecialToCallSuperMethod() {
// int lvarIndex = 0;
// if (!Modifier.isStatic(method.getModifiers())) {
// mv.visitVarInsn(ALOAD, lvarIndex++); // load this
// }
// Utils.createLoadsBasedOnDescriptor(mv, descriptor, lvarIndex);
// mv.visitMethodInsn(INVOKESPECIAL, supertypeName, name, descriptor);
// Utils.addCorrectReturnInstruction(mv, Utils.getReturnTypeDescriptor(descriptor), false);
// }
//
// private void insertThrowNoSuchMethodError() {
// // exception text should look like: a.b.c.B.foo()V
// String text = rtype.getName() + "." + name.replace('/', '.') + descriptor;
// mv.visitTypeInsn(NEW, "java/lang/NoSuchMethodError");
// mv.visitInsn(DUP);
// mv.visitLdcInsn(text);
// mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V");
// mv.visitInsn(ATHROW);
// }
//
// }
//
// class AugmentingConstructorAdapter extends MethodVisitor implements Opcodes {
//
// int ctorId;
//
// String name;
//
// String descriptor;
//
// MethodMember method;
//
// String type;
//
// boolean isTopMost;
//
// public AugmentingConstructorAdapter(MethodVisitor mv, String descriptor, String type, boolean isTopMost) {
// super(ASM5, mv);
// this.descriptor = descriptor;
// this.type = type;
// this.isTopMost = isTopMost;
// }
//
// @Override
// public void visitCode() {
// super.visitCode();
//
// // 1. Quick check if anything has changed
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitLdcInsn(ctorId);
// mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, tReloadableType, "cchanged", "(I)Ljava/lang/Object;");
// // return value of that call is the dispatcher to call, or null if we shouldn't do anything different
//
// // TODO throw exception if no longer defined? (Shouldn't really be called if not defined though...)
//
// // 2. if nothing has changed jump to the end and run the original code
// Label wasNull = new Label();
// mv.visitInsn(DUP);
// mv.visitJumpInsn(Opcodes.IFNULL, wasNull); // if == null
//
// mv.visitTypeInsn(CHECKCAST, Utils.getInterfaceName(slashedname));
// // mv.visitInsn(SWAP);
// mv.visitVarInsn(ALOAD, 0);
// // mv.visitInsn(DUP);
// // Now we have the dispatcher on the stack for our type, we can't pass 'this' (aload_0) on a call yet because it is
/// not initialized
// // have to initialize it now before we can pass it on
// // mv.visitMethodInsn(INVOKESPECIAL, slashedname, "<init>", "(Lorg/springsource/loaded/ReloadableType;)V");
// // mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
// // mv.visitMethodInsn(INVOKESPECIAL, owner, name, desc)
// if (isEnum) {
// mv.visitVarInsn(ALOAD, 1);
// mv.visitVarInsn(ILOAD, 2);
// mv.visitInsn(ACONST_NULL);
// mv.visitMethodInsn(INVOKESPECIAL, slashedname, "<init>",
// "(Ljava/lang/String;ILorg/springsource/loaded/C;)V");
// }
// else {
// mv.visitInsn(ACONST_NULL);
// mv.visitMethodInsn(INVOKESPECIAL, slashedname, "<init>", "(Lorg/springsource/loaded/C;)V");
// }
//
// // initialize the field instance manager
// // not conditional on isTopMost because entering object construction through this route won't ever call the
/// initialization logic in
// // the super ctor, because all that is bypassed. We could put this initialization logic into the topmost 'special'
/// constructor
// // that we create, that is an alternative
// if (GlobalConfiguration.fieldRewriting) {// && isTopMost) {
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(GETFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// Label l1 = new Label();
// mv.visitJumpInsn(IFNONNULL, l1);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitTypeInsn(NEW, tInstanceStateManager);
// mv.visitInsn(DUP);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(INVOKESPECIAL, tInstanceStateManager, "<init>",
// "(Ljava/lang/Object;Lorg/springsource/loaded/ReloadableType;)V");
// mv.visitFieldInsn(PUTFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// mv.visitLabel(l1);
// }
//
// mv.visitVarInsn(ALOAD, 0);
// Utils.createLoadsBasedOnDescriptor(mv, descriptor, 1);
// // from "(Ljava/lang/String;J)V" to "(Ljava/lang/String;J)Lcom/foo/A;"
// // String desc = new StringBuilder().append(descriptor, 0, descriptor.length() - 1).append("L").append(slashedname)
// // .append(";").toString();
//
// // mv.visitMethodInsn(INVOKEVIRTUAL,"")
//
// String desc = new StringBuilder("(L").append(slashedname).append(";").append(
// descriptor.substring(1)).toString();
//
// // mv.visitVarInsn(ALOAD, 0);
// // mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
//
// mv.visitMethodInsn(INVOKEINTERFACE, Utils.getInterfaceName(slashedname), "___init___", desc);
// mv.visitInsn(RETURN);
// // mv.visitTypeInsn(CHECKCAST, type);
//
// // 4. do what you were going to do anyway
// mv.visitLabel(wasNull);
// mv.visitInsn(POP);
// }
//
// int unitializedObjectsCount = 0;
//
// @Override
// public void visitTypeInsn(final int opcode, final String type) {
// if (opcode == NEW) {
// unitializedObjectsCount++;
// }
// super.visitTypeInsn(opcode, type);
// }
//
// @Override
// public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc,
// final boolean itf) {
// super.visitMethodInsn(opcode, owner, name, desc, itf);
// if (opcode == INVOKESPECIAL) {
// unitializedObjectsCount--;
// }
// if (unitializedObjectsCount == -1 && isTopMost) {
// // Need to insert this after the relevant invokespecial
// if (GlobalConfiguration.fieldRewriting) {
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(GETFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// Label l1 = new Label();
// mv.visitJumpInsn(IFNONNULL, l1);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitTypeInsn(NEW, tInstanceStateManager);
// mv.visitInsn(DUP);
// mv.visitVarInsn(ALOAD, 0);
// mv.visitFieldInsn(Opcodes.GETSTATIC, slashedname, fReloadableTypeFieldName, lReloadableType);
// mv.visitMethodInsn(INVOKESPECIAL, tInstanceStateManager, "<init>",
// "(Ljava/lang/Object;Lorg/springsource/loaded/ReloadableType;)V", false);
// // mv.visitMethodInsn(INVOKESPECIAL, tInstanceStateManager, "<init>", "(Ljava/lang/Object;)V");
// mv.visitFieldInsn(PUTFIELD, slashedname, fInstanceFieldsName, lInstanceStateManager);
// mv.visitLabel(l1);
// }
// }
// }
//
// }
//
// interface Prepender {
//
// void prepend();
// }
//
// class MethodPrepender extends MethodVisitor implements Opcodes {
//
// Prepender appender;
//
// public MethodPrepender(MethodVisitor mv, Prepender appender) {
// super(ASM5, mv);
// this.appender = appender;
// }
//
// @Override
// public void visitCode() {
// super.visitCode();
// appender.prepend();
// }
//
// }
//
// }
//
// }
